extern crate base64;
extern crate rand;
extern crate rand_pcg;
extern crate ring;
use self::base64::*;
use self::rand::{Rng, SeedableRng};
use self::rand_pcg::Pcg32;
use self::ring::digest;

use std::io::Cursor;

fn random_config(data: &[u8]) -> Config {

    // use sha256 of data as rng seed so it's repeatable
    let sha = digest::digest(&digest::SHA256, data);

    let mut seed: [u8; 16] = [0; 16];
    seed.copy_from_slice(&sha.as_ref()[0..16]);

    let mut rng = Pcg32::from_seed(seed);

    let charset = if rng.gen() {
        CharacterSet::UrlSafe
    } else {
        CharacterSet::Standard
    };

    Config::new(charset, rng.gen(), rng.gen(),  LineWrap::NoWrap)
}

#[inline(always)]
pub fn fuzz_base64_roundtrip_random_config(data: &[u8]) {
    let config = random_config(data);
    let encoded = encode_config(&data, config);
    let decoded = decode_config(&encoded, config).unwrap();
    //assert_eq!(data, decoded.as_slice());
}


#[inline(always)]
pub fn fuzz_base64(data: &[u8]) {
    let encoded = base64::encode_config(&data, base64::STANDARD);
    let decoded = base64::decode_config(&encoded, base64::STANDARD).unwrap();
    //assert_eq!(data, decoded.as_slice());
}

// #[inline(always)]
// pub fn fuzz_claxon(data: &[u8]) {
//     let cursor = Cursor::new(data);
//     // println!("{}", data.len());
//     let mut reader = match claxon::FlacReader::new(cursor) {
//         Ok(r) => r,
//         Err(..) => return,
//     };

//     for sample in reader.samples() {
//         match sample {
//             Ok(..) => { }
//             Err(..) => return,
//         }
//     }
// }

mod smallvec_fuzz;
pub fn fuzz_smallvec1(data: &[u8]) {
    smallvec_fuzz::smallvec1_t_103(data);
}

pub fn fuzz_smallvec2(data: &[u8]) {
    smallvec_fuzz::smallvec2_t_2019_0009(data);
}

mod slice_deque_fuzz;
pub fn fuzz_slice_deque(data: &[u8]) {
    slice_deque_fuzz::fuzz_slice_deque(data);
}

mod simple_input;
pub fn fuzz_claxon(data: &[u8]) {
    simple_input::run_claxon(data);
}

pub fn fuzz_simd_json(data: &[u8]) {
    simple_input::run_simd_json(data);
}

pub fn fuzz_libflate(data: &[u8]) {
    simple_input::run_libflate_gzip(data);
}

pub fn fuzz_safe_transmute(data: &[u8]) {
    simple_input::run_safe_transmute(data);
}

pub fn fuzz_image(data: &[u8]) {
    simple_input::run_test_image(data);
}

mod core_utils;
pub fn fuzz_core_base64(data: &[u8]) {
    core_utils::run_code_util_base64(data);
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
